package NG::Chat::Client::Proxy;
use strict;
use warnings;

use Data::Dumper;
#use NG::Chat::Util;
use EV;
use JSON::XS;
use Queue::Mmap;

use base 'NG::Chat::Client::Handler';

sub new {
	my $class = shift;
	my $client = shift;
	my $app = shift;
	my $self = $class->SUPER::new($client);
	$self->{queue} = Queue::Mmap->new(
		file => $app->{cfg}{path}{cache}."/".$app->{queue}{file},
		queue => $app->{queue}{queue},
		length => $app->{queue}{length},
	);
	$app->logger->info("queue: ".join(":",$self->{queue}->stat));
	$self->{send_count} = 0;
	my $log = $app->logger;

	if(my $interval = $app->{stat_log_interval}){
		$self->{stat_log_interval} = EV::timer $interval,$interval,sub {
			if($self->{send_count}){
				$log->info("STAT wait: ".$self->{wait}." length: ".$self->{queue}->length." count: ".$self->{send_count});
				$self->{send_count} = 0;
			}
		};
	}
	my $wait;
	if(my $wait_auto = $app->{wait_auto}){
		$wait = $self->{wait} = 0.01;
		$self->{wait_tune} = EV::timer $wait_auto,$wait_auto,sub {
			my $length = $self->{queue}->length;
			unless($length){
				if($self->{wait} < 0.05){
					$self->{wait} += 0.001;
				}else{
					$self->{wait} = 0.05;
					return;
				}
			}elsif($length > 100 ){
				if($self->{wait} > 0.005){
					$self->{wait} -= 0.005;
				}elsif($self->{wait} > 0.001){
					$self->{wait} -= 0.001;
				}else{
					$self->{wait} = 0.001;
					return;
				}
			}elsif($length > 50 ){
				if($self->{wait} > 0.001){
					$self->{wait} -= 0.001;
				}else{
					$self->{wait} = 0.001;
					return;
				}
			}else{
				return;
			}
			$self->{input}->set($self->{wait},$self->{wait});
			$log->info("TUNE length: ".$length." wait: ".$self->{wait});
		};
	}else{
		$wait = $self->{wait} = $app->{wait_timeout} || 0.1;
	}
	$self->{to_send} = [];

	$self->{input} = EV::timer_ns $wait, $wait, sub {check_queue($self)};
	my $l = $app->{chat_login};
	my $p = $app->{chat_pass};
	
	$self->{loginer} = EV::timer_ns 30, 30, sub {
		$log->info("try login");
		$self->{client}->send_message({
			cmd => "login",
			login => $l,
			pass => $p,
		});
	};
	$self->relogin();
	return $self;
}
sub cleanup {
	my $self = shift;
	$self->SUPER::cleanup;
	delete $self->{queue};
	delete $self->{input};
	delete $self->{loginer};
	delete $self->{wait_tune};
	delete $self->{stat_log_interval};
}
sub relogin {
	my $self = shift;
	my $obj = shift;
	if($obj){
		push @{$self->{to_send}},$obj;
	}
	$self->{loginer}->invoke;
	$self->{loginer}->start;
}
sub check_queue {
	my $self = shift;
	my $client = $self->{client};
	while(my $obj = shift @{$self->{to_send}}){
		if(!$client->{sid} || $client->send_message($obj)){
			$self->{input}->stop;
			$self->relogin($obj);
			return;
		}
	}
	my $full = 100;
	while(my $str = $self->{queue}->pop){
		my $obj = decode_json($str);
		if(!$client->{sid} || $client->send_message($obj)){
			$self->{input}->stop;
			$self->relogin($obj);
			return;
		}
		$self->{send_count}++;
		if(--$full<0){
			last;
		}
	}
	$self->{input}->again;
}

sub make_process_response {
	my $self = shift;
	return sub {
		my $client = shift;
		my $msg = shift;
		my $ret = 0;
		if($msg->{type} eq "list"){
			for(sort {$a->{ats} <=> $b->{ats}} @{$msg->{list}}){
				process_one_response($client,$_);
			}
			$ret =  1;
		}else{
			$ret = process_one_response($client,$msg);
		}
		if($ret>0){
			$self->{input}->start;
			$self->{loginer}->stop;
		}elsif($ret < 0){
			$self->{input}->stop;
			$self->relogin;
			$ret = 0;
		}
		return $ret;
	};
}
sub process_one_response {
	my $client = shift;
	my $msg = shift;
	if($msg->{type} eq "response"){
		if($msg->{error}){
			if($msg->{error} == 401){
				$client->{sid} = "";
				return -1;
			}
		}
	}
	elsif($msg->{type} eq "notice"){
		if($msg->{param1} eq "welcome"){
			$client->{sid} = $msg->{sid};
			$client->{login} = $msg->{param3};
			$client->{chanel} = $msg->{chanel};
			return 1;
		}
	}
	return 0;
}

1;
